home *** CD-ROM | disk | FTP | other *** search
- /*
- File: CRDManagement.c
-
- Contains: QuickDraw GX to PostScript conversion code.
- This file contains code to manage color rendering dictionaries
- for PostScript color matching.
-
- Version: Technology: Quickdraw GX 1.1.x
-
- Copyright: © 1996-1997 by Apple Computer, Inc., all rights reserved.
- */
-
- #include "GXToPSBuildConfig.h"
- #include <GXGraphics.h>
- #include "GXGraphicsPriv.h"
- #include <GXEnvironment.h>
- #include "GXToPostScript.h"
- #include "IOUtilities.h"
- #include "RDUtil.h"
- #include "FontHandler.h"
- #include "PublicPostScriptIE.h"
- #include "private.h"
- #include "PSIEResources.h"
- #include "GXErrors.h"
- #include "ShapeUtilities.h"
-
- #include <CMICCProfile.h>
- #include <CMApplication.h>
-
- #ifdef resumeLabel
- #undef resumeLabel
- #endif
- #define resumeLabel(exception)
-
-
-
-
- /*--------------------------------CRD Downloading stuff-------------------------------------------*/
-
- /*********************************
-
- Streaming function for ICC Profile streaming stuff.
- This function is used for sending postscript data for
- ICC profiles.
-
- The imaging engine globals are passed as the refcon.
-
- command: ColorSync stream command.
- size: how many bytes to write (by reference)
- data: pointer to bytes to write.
- hIEGlobals: Imaging engine globals.
-
- *********************************/
- pascal OSErr ICCProfileStreamProc(long command, long *size, void *data, TIEGlobalsHdl hIEGlobals)
- {
- OSErr status = noErr;
-
- switch(command) {
-
- case cmCloseSpool:
- #if DEBUGLEVEL > 0
- if (*size > 0)
- dprintf(trace, "Funny, size on close is non-zero. Ignoring data");
- status = (*hIEGlobals)->psDevice->BufferData("\n%- End of ColorSync streamed data\n", 35, gxNoBufferOptions);
- #endif
- nrequire(status, failed_close);
- break;
-
- case cmOpenWriteSpool:
- status = RDFlushBuffer((*hIEGlobals)->rdMap);
- nrequire(status, failed_rdFlush);
- #if DEBUGLEVEL > 0
- if (*size > 0)
- dprintf(trace, "Funny, size on open is non-zero. Ignoring data");
- status = (*hIEGlobals)->psDevice->BufferData("\n%- Start of ColorSync streamed data\n", 37, gxNoBufferOptions);
- nrequire(status, failed_open);
- #endif
- break;
-
- case cmWriteSpool:
- if (*size > 0)
- status = (*hIEGlobals)->psDevice->BufferData((char*)data, *size, gxNoBufferOptions); // hexification should be handled by ColorSync itself.
- nrequire(status, failed_write);
- break;
-
-
- case cmReadSpool:
- case cmOpenReadSpool:
- default:
- #if DEBUGLEVEL > 0
- dprintf(notrace, "Unsupported profile stream command: %d", command);
- #endif
- status = colorSpace_out_of_range; /* for lack of something better to return - this should never happen anyway */
-
- }//end switch
-
- failed_write:
- failed_close:
- failed_open:
- failed_rdFlush:
-
- return(status);
-
- }//ICCProfileStreamProc
-
-
-
- /*********************************
-
- Another Streaming function for ICC Profile streaming stuff.
- This one is used to load a string with the rendering inent name only.
-
- command: ColorSync stream command.
- size: how many bytes to write (by reference)
- data: pointer to bytes to write.
- hIEGlobals: Imaging engine globals.
-
- *********************************/
- pascal OSErr NameStreamProc(long command, long *size, void *data, Str255 name);
- pascal OSErr NameStreamProc(long command, long *size, void *data, Str255 name)
- {
- OSErr status = noErr;
- unsigned long length;
-
- switch(command) {
-
- case cmCloseSpool:
- /* Rewind length to eliminate trailing white spaces */
- length = (unsigned char)name[0];
- while ( (length > 0) && ((name[length] == ' ') || (name[length] == '\r') || (name[length] == '\n') ) )
- --length;
-
- name[0] = length;
-
- break;
-
- case cmOpenWriteSpool:
- name[0] = 0; // Initialize the length.
- break;
-
- case cmWriteSpool:
- length = (unsigned char)name[0];
- if ( (length + *size) >= 100 )
- *size = 100 - length;
-
- BlockMoveData(data, &(name[length+1]), *size);
- length += *size;
- name[0] = length;
-
- break;
-
- case cmReadSpool:
- case cmOpenReadSpool:
- default:
- #if DEBUGLEVEL > 0
- dprintf(notrace, "Unsupported profile stream command: %d", command);
- #endif
- status = colorSpace_out_of_range; /* for lack of something better to return - this should never happen anyway */
-
- }//end switch
-
- return(status);
-
- }//NameStreamProc
-
-
- /*------------------------------------------------------------------------------------------*/
-
-
- /***
- The imaging engine will maintain a list of tags on the device profile.
- Each tag will contain info for the CRD of a particular rendering intent
- requested.
- ***/
- // Tag type for device profile CRD information
- #define crdInfoTagType 'pscd'
-
- typedef struct {
-
- /*
- intent and flags will key our database. Note, this database key will return
- false positive should there ever be a CMM that would download a different CRD for the same
- dest profile for a source profile that had the same intent and flags as another source profile
- Steve Swen (Lead ColorSync guy) assures me that this is sufficient 11/1/96.
- */
-
- unsigned long flags; // profile flags this CRD is for?
- unsigned long renderingIntent; // Which rendering intent is this for?
-
-
- unsigned char psName[129]; // this will be the PostScript name, as pascal string
- unsigned long vmUsage; // How much VM does it use?
- Boolean onPrinter; // Is it already downloaded?
- Boolean isDocLevel; // Is it downloaded document level?
-
- } TcrdInfoRec;
-
-
-
-
- /************************
-
- Routine constructs the PostScript name for the CRD
-
- Name will be the rendering intent appended with "Mac.none".
- This seems to be what the LaserWriter 8.x driver does.
-
- Note, keep this in sync with code in GXFindCRDName in Level2ColorProcs.ps
-
- *************************/
- OSErr ConstructCRDpsName(CMProfileRef sourceProfile, Str255 name);
- OSErr ConstructCRDpsName(CMProfileRef sourceProfile, Str255 name)
- {
- OSErr status;
-
- Boolean preferredCMMNotFound;
- CMFlattenUPP streamProc = NewCMFlattenProc(NameStreamProc); // note assuming this segment stays locked since it is in call-chain.
-
- /* First put the rendering intent at the beginning of name */
-
- status = CMGetPS2ColorRenderingIntent(sourceProfile, cmPS7bit, streamProc, name, &preferredCMMNotFound);
- DisposeRoutineDescriptor(streamProc);
- nrequire(status, failed_cs2Stream);
-
- /* Now append suffix to it. */
-
- BlockMoveData(".Mac.none", &(name[name[0]+1]), 9);
- name[0] += 9;
-
- failed_cs2Stream:
- return(status);
-
- }//ConstructCRDpsName
-
- /**********************************************
-
- FindOrAddIntentInfoToProfile:
-
- This routine retrieves the tag on the gx-profile
- containing the CRD info for the desired
- rendering intent.
-
- ***********************************************/
- OSErr FindOrAddIntentInfoToProfile(gxColorProfile theGXDstProfile, CMProfileRef sourceProfile, gxTag *crdInfoTag);
- OSErr FindOrAddIntentInfoToProfile(gxColorProfile theGXDstProfile, CMProfileRef sourceProfile, gxTag *crdInfoTag)
- {
- OSErr status;
- long numCRDsSoFar;
- long idx;
- Boolean foundIt = false;
- TcrdInfoRec crdInfo;
- TcrdInfoRec* crdInfoPtr;
- CMProfileRef theDstProfile;
- CMAppleProfileHeader profHeader;
- Boolean prefferendNotFound;
-
- status = CMGetProfileHeader(sourceProfile, &profHeader);
- nrequire(status, failed_getheader);
-
- *crdInfoTag = nil;
- numCRDsSoFar = GXGetColorProfileTags(theGXDstProfile, crdInfoTagType, 1, gxSelectToEnd, nil);
-
- #if DEBUGLEVEL > 0
- dprintf(trace, "# of CRDs databased so far on dest profile: %d", numCRDsSoFar);
- #endif
-
- /* Search all the tags on the profile for the one we want */
- for (idx = 1; idx <= numCRDsSoFar; ++idx) {
-
- GXGetColorProfileTags(theGXDstProfile, crdInfoTagType, idx, 1, crdInfoTag);
- crdInfoPtr = (TcrdInfoRec*)GXGetTagStructure(*crdInfoTag, nil);
-
- /* we found it, exit the loop */
- if ( (crdInfoPtr->renderingIntent == profHeader.cm2.renderingIntent) && (crdInfoPtr->flags == profHeader.cm2.flags) ) {
- foundIt = true;
- break;
- }//end if
-
- nrequire(status = GXGetGraphicsError(nil), failed_gettag);
-
- }//end for
-
- /* If we didn't find the tag for our rendering intent in the profile, make it and add it */
-
- if (!foundIt) {
-
- #if DEBUGLEVEL > 0
- dprintf(trace, "CRD hasn't been added to dest profile database yet, adding now");
- #endif
-
- theDstProfile = GXGetColorProfileReference(theGXDstProfile);
-
- crdInfo.renderingIntent = profHeader.cm2.renderingIntent;
- crdInfo.flags = profHeader.cm2.flags;
- crdInfo.onPrinter = false;
- crdInfo.isDocLevel = false;
- status = ConstructCRDpsName(sourceProfile, crdInfo.psName);
- nrequire(status, failed_name);
-
- status = CMGetPS2ColorRenderingVMSize(sourceProfile, theDstProfile, &(crdInfo.vmUsage), &prefferendNotFound);
- nrequire(status, failed_VM);
-
- *crdInfoTag = GXNewTag(crdInfoTagType, sizeof(TcrdInfoRec), &crdInfo);
- GXSetColorProfileTags(theGXDstProfile, crdInfoTagType, 0, 0, 1, crdInfoTag);
- GXDisposeTag(*crdInfoTag); // The profile owns this now, so decrement the owner count.
-
- status = GXGetGraphicsError(nil); // just checking.
- nrequire(status, failed_makeTag);
-
- }//end if
-
- failed_makeTag:
- failed_VM:
- failed_name:
- failed_gettag:
- failed_getheader:
-
- return(status);
-
- }//FindOrAddIntentInfoToProfile
-
-
- //<FF>
- /**********************************************
-
- MakeCRDAvailable:
-
- This function ensures that the desired CRD is available
- on the printer. If a destination profile other than the printers
- default (indicated by the device profile being the zero length
- profile) is specified, then this routine will
- download the CRD if it has not already been downloaded
- prior to this request
-
-
- sourceProfile: The profile of the source data we need for which we need the correct
- device profile's CRD
-
- ***********************************************/
- OSErr MakeCRDAvailable(TIEGlobalsHdl hIEGlobals, CMProfileRef sourceProfile)
- {
- OSErr status = noErr;
- gxColorProfile destProfileGX;
- CMProfileRef destProfile;
- gxTag infoTag;
- TcrdInfoRec *crdInfoPtr;
- TRDParams* pRDParams = (*hIEGlobals)->pRDParams;
-
- destProfileGX = (*hIEGlobals)->params.devCProfile;
- destProfile = GXGetColorProfileReference( destProfileGX );
-
- if ( destProfile != nil ) {
-
- /* non-zero length ICC profile, make sure the CRD is available on the printer */
-
- // Find our tag on the gxProfile reference for this rendering intent, or make one.
-
- status = FindOrAddIntentInfoToProfile(destProfileGX, sourceProfile, &infoTag);
- nrequire(status, failed_findInfo);
-
- // Now, download the CRD specified by the tag, if it is not already there.
-
- GXLockTag(infoTag);
- crdInfoPtr = (TcrdInfoRec*)GXGetTagStructure(infoTag, nil);
-
- if ( !crdInfoPtr->onPrinter) {
-
- /* Download and name the CRD */
-
- Boolean preferredCMMNotFound;
- CMFlattenUPP streamProc = NewCMFlattenProc(ICCProfileStreamProc); // note assuming this segment stays locked since it is in call-chain.
-
- /* Download the CRD into global VM */
-
- pRDParams->resIndex = kSetGlobalVM; // note, this leaves global state on stack.
- status = RDResPrintf(pRDParams, (long)true);
- nrequire(status, failed_global_on);
-
- /* do the actual download */
-
- status = CMGetPS2ColorRendering(sourceProfile, destProfile, ((*hIEGlobals)->params.renderOptions & gxNeedsHexOption) ? cmPS7bit : cmPS8bit,
- streamProc, hIEGlobals, &preferredCMMNotFound);
-
- DisposeRoutineDescriptor(streamProc);
- nrequire(status, failed_streamCRD);
-
- /* Now define the CRD resource */
-
- pRDParams->resIndex = kDefineCRD;
- status = RDResPrintf(pRDParams, crdInfoPtr->psName);
- nrequire(status, failed_defineCRD);
-
- pRDParams->resIndex = kRestoreGlobalVM;
- status = RDResPrintf(pRDParams);
- nrequire(status, failed_global_off);
-
- crdInfoPtr->onPrinter = true;
-
- } else {
-
- #if DEBUGLEVEL > 0
- dprintf(trace, "Requested CRD is already on printer: %P", crdInfoPtr->psName);
- #endif
-
- }//end if
-
- failed_global_off:
- failed_defineCRD:
- failed_streamCRD:
- failed_global_on:
-
- GXUnlockTag(infoTag);
-
- }//end if
-
-
- failed_findInfo:
- return(status);
-
- }//MakeCRDAvailable
-
-
-
-
- /**********************************************
-
- RemoveDownloadedCRDs:
-
- This function removes from PostScript VM any CRDs
- that were downloaded for the device profile.
-
- This routine should be called at the end of each page
- when generating Page Independent PostScript.
-
- ***********************************************/
- OSErr RemoveDownloadedCRDs(TIEGlobalsHdl hIEGlobals)
- {
- OSErr status = noErr;
- gxColorProfile destProfileGX;
- gxTag infoTag;
- TcrdInfoRec *crdInfoPtr;
- long idx, count;
- TRDParams* pRDParams = (*hIEGlobals)->pRDParams;
- Boolean tagLocked = false;
-
- destProfileGX = (*hIEGlobals)->params.devCProfile;
-
- if (destProfileGX == nil)
- return noErr;
-
- count = GXGetColorProfileTags(destProfileGX, crdInfoTagType, 1, gxSelectToEnd, nil);
- if (count > 0) {
-
- #if DEBUGLEVEL > 0
- status = RDFlushBuffer((*hIEGlobals)->rdMap);
- if (status == noErr)
- status = (*hIEGlobals)->psDevice->BufferData("\n%- Cleaning up downloaded CRDs\n", 32, gxNoBufferOptions);
-
- nrequire(status, failed_debuggingComment);
- #endif
-
- /* Since CRD's are defined in global-VM, undefine them in global-VM too! */
-
- pRDParams->resIndex = kSetGlobalVM; // note, this leaves global state on stack.
- status = RDResPrintf(pRDParams, (long)true);
- nrequire(status, failed_global_on);
-
- /* Loop on each CRD associated with the device profile */
-
- for (idx = 1; idx <= count; ++idx) {
-
- GXGetColorProfileTags(destProfileGX, crdInfoTagType, idx, 1, &infoTag);
- GXLockTag(infoTag);
- tagLocked = true;
- crdInfoPtr = (TcrdInfoRec*)GXGetTagStructure(infoTag, nil);
-
- /* If the CRD has been downloaded, but not for whole document, undefine it from VM */
-
- if (crdInfoPtr->onPrinter && (!crdInfoPtr->isDocLevel) ) {
-
- pRDParams->resIndex = kUndefineCRD;
- status = RDResPrintf(pRDParams, crdInfoPtr->psName);
- nrequire(status, failed_undefine);
-
- crdInfoPtr->onPrinter = false; // mark it undlownloaded.
-
- }//end if
-
- GXUnlockTag(infoTag);
- tagLocked = false;
-
- }//end for
-
- /* Restore global-vm state */
-
- pRDParams->resIndex = kRestoreGlobalVM;
- status = RDResPrintf(pRDParams);
- nrequire(status, failed_global_on);
-
- }//end if
-
- failed_undefine:
- failed_global_on:
- failed_debuggingComment:
-
- if (tagLocked) // in case an error happened and we get down here before tag was unlocked in loop.
- GXUnlockTag(infoTag);
-
- return(status);
-
- }//RemoveDownloadedCRDs
-